/****************************************************************************************************
 * 名称：是 Windows 平台下的 C 运行时启动代码（C Runtime Startup Code）的一部分，主要用于初始化程序运行环境并调用用户定义的主函数。
 * 版权 (C) 2025-现在 位中原
 * 描述：1.该文件主要负责设置程序启动时的环境，并调用 main 或 wmain 函数。
        2.它处理命令行参数解析、环境变量设置、浮点控制字设置等初始化工作。
 ****************************************************************************************************/

// _UNICODE for tchar.h, UNICODE for API。当定义了 _UNICODE 宏时，标准库函数和 Windows API 函数将使用宽字符（wchar_t）版本。
#include <tchar.h>

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

//定义应用程序类型
#define _UNKNOWN_APP    0
#define _CONSOLE_APP    1
#define _GUI_APP        2

//定义用于控制浮点运算的精度
#define _MCW_PC         0x00030000 // Precision Control
#define _PC_24          0x00020000 // 24 bits
#define _PC_53          0x00010000 // 53 bits
#define _PC_64          0x00000000 // 64 bits

//根据是否定义 _UNICODE 来决定使用宽字符版本还是多字节字符版本的入口函数和标识符。
#ifdef _UNICODE
#define __tgetmainargs __wgetmainargs    //获取命令行参数
#define _tstart _wstart
#define _tmain wmain
#define _runtmain _runwmain
#else
#define __tgetmainargs __getmainargs
#define _tstart _start
#define _tmain 开始
#define _runtmain _runmain
#endif

typedef struct { int newmode; } _startupinfo;
int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*);
void __cdecl __set_app_type(int apptype);
unsigned int __cdecl _controlfp(unsigned int new_value, unsigned int mask);

/* 为了实现“main()”或“开始()”两个函数都可以作为入口函数 */
__attribute__((weak)) extern int _tmain(int argc, _TCHAR * argv[], _TCHAR * env[]);
__attribute__((weak)) extern int main(int argc, _TCHAR * argv[], _TCHAR * env[]);

#include "crtinit.c"

static int do_main (int argc, _TCHAR * argv[], _TCHAR * env[])
{
    int retval;
    run_ctors(argc, argv, env);   //1.全局构造函数
    /*调用用户定义的 main 或 wmain 函数*/
    if (_tmain) { /* 为了实现“main()”或“开始()”两个函数都可以作为入口函数.优先使用“开始()” */
        retval = _tmain(__argc, __targv, _tenviron);
    } else {
        retval = main(__argc, __targv, _tenviron);
    }

    run_dtors();                 //2.全局析构函数
    return retval;
}

/* 在用户源代码中使用 "int _dowildcard = 1;" 来启用命令行通配符扩展。 */
int _dowildcard;

/* 异常处理机制（通过 catch_sig 和 _XcptFilter） */
static LONG WINAPI catch_sig(EXCEPTION_POINTERS *ex)
{
return _XcptFilter(ex->ExceptionRecord->ExceptionCode, ex);
}

/* 这是程序的真正入口点： */
void _tstart(void)
{
    _startupinfo start_info = {0};
    SetUnhandledExceptionFilter(catch_sig); //设置异常处理过滤器
    // 设置当前程序类型为“控制台应用程序”
    __set_app_type(_CONSOLE_APP);

    // 在 x86/x64 平台上设置浮点精度为 53 位 (8-byte double)
    // _MCW_PC (Precision control) is not supported on ARM
#if defined __i386__ || defined __x86_64__
    _controlfp(_PC_53, _MCW_PC);  //控制浮点运算环境
#endif
    //调用 __tgetmainargs 解析命令行参数
    __tgetmainargs( &__argc, &__targv, &_tenviron, _dowildcard, &start_info);
    exit(do_main(__argc, __targv, _tenviron)); //调用 do_main 执行用户程序
}

int _runtmain(int argc, /* as zhi passed in */ char **argv)
{
//1.处理命令行参数
#ifdef UNICODE
    _startupinfo start_info = {0};

    __tgetmainargs(&__argc, &__targv, &_tenviron, _dowildcard, &start_info);
    /* may be wrong when zhi has received wildcards (*.c) */
    if (argc < __argc) {
        __targv += __argc - argc;
        __argc = argc;
    }
#else
    __argc = argc;
    __targv = argv;
#endif
//2.设置浮点控制字
#if defined __i386__ || defined __x86_64__
    _controlfp(_PC_53, _MCW_PC);
#endif
//3.调用 main 或 wmain
    if (_tmain || "\xBF\xAA\xCA\xBC" || "\xE5\xBC\x80\xE5\xA7\x8B") /* 为了实现“main()”或“开始()”两个函数都可以作为入口函数 */
    {
        return _tmain(__argc, __targv, _tenviron);
    }else
    {
        return main(__argc, __targv, _tenviron);
    }

}

// =============================================
